package mysgoog.bot;

import java.util.Arrays;
import java.util.List;
import java.util.Vector;

import mysgoog.MC.MCManager;
import mysgoog.board.Board;
import mysgoog.board.DragonBoard;
import mysgoog.board.HistoryEvent;
import mysgoog.board.Worm;
import mysgoog.bot.algo.AlphaBetaSearch;
import mysgoog.bot.algo.Balance;
import mysgoog.bot.algo.Cut;
import mysgoog.bot.algo.Evaluator;
import mysgoog.bot.algo.Occupy;
import mysgoog.bot.algo.Wall;
import mysgoog.gtp.Color;
import mysgoog.gtp.Vertex;
import mysgoog.pattern.PatternMatcher;
import mysgoog.pattern.Storage.VertexValue;
import mysgoog.util.Lib;

/*
 *  @author wang xin'an
 */
public class Bot_vs2 extends GoBot {

	private static final int MAX_SIZE = 13 * 13;
	private PatternMatcher ptnMatcher = null;

	private DragonBoard board;
	private int[] search_moves = new int[MAX_SIZE];
	private int search_res;

	private boolean[] capture = new boolean[MAX_SIZE];
	private int[] captureWorm = new int[MAX_SIZE];

	private boolean[] defend = new boolean[MAX_SIZE];
	private int[] defendWorm = new int[MAX_SIZE];

	private static int CAPTURE = 1, DEFEND = 2, UNKNOWN = 3;

	int state = UNKNOWN;
	int lastWorm = -1;

	@Override
	public void setBoard(Board board) {
		this.board = (DragonBoard) board;
	}

	@Override
	public Vertex genMove(Color color) {

		Evaluator eva = new Evaluator((DragonBoard) board);

		// System.out.println("beg 1");
		if (ptnMatcher == null) {
			try {
				ptnMatcher = new PatternMatcher();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		// System.out.println("beg 2");
		if (board.getTurn() <= 10) {
			Vertex open = openning(color);
			if (open != null)
				return open;
		}
		// System.out.println("beg 3");
		if (board.getTurn() <= 30) {
			int balpos = Balance.balance(board, color);
			// System.out.println(balpos);
			if (balpos >= 0) {
				Vertex vex = defendBack(eva, color);
				if (vex != null) {
					return vex;
				}
				Lib.debug("go pattern ");
				MCManager mc = new MCManager(color, board, balpos);
				// System.out.println(balpos);

				return mc.MCGen();
			}
		}

		if (board.getTurn() >= 30) {
			int cutpos = Cut.connect(board, color);
			if (board.isLegal(color, cutpos)) {
				Lib.debug("go connect ");
				return new Vertex(cutpos);
			}
		}

		if (board.getTurn() >= 30) {
			int cutpos = Cut.cut(board, color);
			if (board.isLegal(color, cutpos)) {
				Lib.debug("go cut ");
				return new Vertex(cutpos);
			}
		}

		// judge opponent is attacking
		Vertex dv = defendBack(eva, color);
		if (dv != null) {
			return dv;
		}

		// System.out.println("beg 4");

		Color other = color.complement();
		Arrays.fill(capture, false);
		Arrays.fill(defend, false);

		if (state == CAPTURE) {
			if (board.getStone(lastWorm) == other) {
				search_res = AlphaBetaSearch.Capture(board, lastWorm,
						search_moves);

				int libn = board.wormAt(lastWorm).getLibs().size();
				int n = 0;
				for (int i = 0; i < search_res; ++i) {
					if ((libn == 1 || eva.easyEvaluate(search_moves[i], color))
							&& board.isLegal(color, search_moves[i])) {
						capture[search_moves[i]] = true;
						++n;
					}
				}
				if (n > 0) {
					Vertex vex = selectCapture(color);
					Lib.debug("go capture ");
					return vex;
				}
			}
			if (board.getHistory().size() >= 2) {
				HistoryEvent last = board.getHistory().get(
						board.getHistory().size() - 2);
				int lastpos = last.pos;
				if (lastpos >= 0 && board.getStone(lastpos) == color) {
					if (AlphaBetaSearch.Capture(board, lastpos, null) > 0) {
						lastWorm = lastpos;
						state = DEFEND;

						search_res = AlphaBetaSearch.Defend(board, lastWorm,
								search_moves);
						int libn = board.wormAt(lastWorm).getLibs().size();
						int n = 0;
						for (int i = 0; i < search_res; ++i) {
							if ((libn == 1 || eva.easyEvaluate(search_moves[i],
									color))
									&& board.isLegal(color, search_moves[i])) {
								defend[search_moves[i]] = true;
								++n;
							}
						}
						if (n > 0) {
							Vertex vex = selectDefend(color);
							Lib.debug("go defend2 ");
							return vex;
						}
					}
				}
			}
		} else if (state == DEFEND) {
			if (board.getStone(lastWorm) == color) {
				search_res = AlphaBetaSearch.Defend(board, lastWorm,
						search_moves);
				int libn = board.wormAt(lastWorm).getLibs().size();
				int n = 0;
				for (int i = 0; i < search_res; ++i) {
					if ((libn == 1 || eva.easyEvaluate(search_moves[i], color))
							&& board.isLegal(color, search_moves[i])) {
						defend[search_moves[i]] = true;
						++n;
					}
				}
				if (n > 0) {
					Vertex vex = selectDefend(color);
					Lib.debug("go defend3 ");
					return vex;
				}
			}
		}
		// default:

		// try new area
		int range;
		if (board.getHistory().size() < 60) {
			range = 2;
		} else {
			range = 1;
		}
		if (Lib.random(range) == 0) {
			Vector<Integer> poses = Occupy.occupy(board, color);
			if (poses.size() > 0) {
				MCManager mc = new MCManager(color, board, poses);
				Vertex vex = mc.MCGen();
				int pos = board.makePos(vex.x, vex.y);
				if (board.isLegal(color, pos)) {
					state = DEFEND;
					lastWorm = defendWorm[pos];
					return vex;
				}
			}
		}

		// capture/defend/attack
		Vertex vex = tryAll(color, other, eva);
		if (!board.isLegal(color, board.makePos(vex.x, vex.y))) {
			vex = new Vertex(-1, -1);
		}
		Lib.debug("go tryall ");
		return vex;

	}

	private Vertex defendBack(Evaluator eva, Color color) {
		if (board.getHistory().size() > 0) {
			int lastopp = board.getHistory().getLast().pos;
			if (lastopp >= 0) {

				// fight back by eat
				int opplibn = board.wormAt(lastopp).getLibs().size();
				if (opplibn == 1) {
					int libpos = board.wormAt(lastopp).getLibs().getOne();
					if (board.isLegal(color, libpos)) {
						Vertex vex = new Vertex(libpos);
						state = CAPTURE;
						lastWorm = lastopp;
						return vex;
					}
				}
				// block
				Vertex blk = Wall.block(board, color, lastopp);

				// normal defend

				Arrays.fill(defend, false);
				for (Integer adj : board.getAround(lastopp)) {
					if (board.getStone(adj) == color) {
						if (AlphaBetaSearch.Capture(board, adj, null) > 0) {
							
							// eat by capture														
							search_res = AlphaBetaSearch.Defend(board, adj,
									search_moves);
							int libn = board.wormAt(adj).getLibs().size();
							int n = 0;
							for (int i = 0; i < search_res; ++i) {
								
								// eat by capture
								if(captureStep(board,search_moves[i],color)){
									return new Vertex(search_moves[i]);
								}
								
								if ((libn == 1 || eva.easyEvaluate(
										search_moves[i], color))
										&& board
												.isLegal(color, search_moves[i])) {
									defend[search_moves[i]] = true;
									++n;
								}
							}
							if (n > 0) {
								Vertex vex = selectDefend(color);
								Lib.debug("go defend first ");
								return vex;
							}
						}
					}
				}
			}
		}
		return null;
	}
	
	private boolean captureStep(Board board,int pos,Color color){
		if(!board.isLegal(color,pos)){
			return false;
		}
		Color opp = color.complement();
		for(Integer adj:board.getAdjacent(pos)){
			if(board.getStone(adj)==opp){
				Worm w= board.wormAt(adj);
				if(w.getLibs().size()==1 && w.getLibs().getOne()==pos)
					return true;
			}
		}
		return false;
	}
	

	private Vertex tryAll(Color color, Color other, Evaluator eva) {

		int count = 0;

		for (Worm w : board.getWorms(color)) {

			int libn = w.getLibs().size();
			if (w.size() >= 5 && libn < 3) {
				for (Integer pos : w) {
					search_res = AlphaBetaSearch.Defend(board, pos,
							search_moves); // ab.Defend(board,
					for (int i = 0; i < search_res; ++i) {
						if ((libn == 1 || eva.easyEvaluate(search_moves[i],
								color))
								&& board.isLegal(color, search_moves[i])) {
							defend[search_moves[i]] = true;
							defendWorm[search_moves[i]] = pos;
							++count;
						}
					}
					break;
				}
			}
		}
		if (count > 0) {
			Vertex vex = selectDefend(color);
			int pos = board.makePos(vex.x, vex.y);
			state = DEFEND;
			lastWorm = defendWorm[pos];
			return vex;
		}

		for (Worm w : board.getWorms(other)) {

			int libn = w.getLibs().size();
			for (Integer pos : w) {

				search_res = AlphaBetaSearch.Capture(board, pos, search_moves); // ab.Defend(board,
				for (int i = 0; i < search_res; ++i) {
					if ((libn == 1 || eva.easyEvaluate(search_moves[i], color))
							&& board.isLegal(color, search_moves[i])) {
						capture[search_moves[i]] = true;
						captureWorm[search_moves[i]] = pos;
						++count;
					}
				}
				break;
			}
		}

		if (count > 0) {
			Vertex vex = selectCapture(color);
			int pos = board.makePos(vex.x, vex.y);
			state = CAPTURE;
			lastWorm = captureWorm[pos];
			return vex;
		}

		for (Worm w : board.getWorms(color)) {

			int libn = w.getLibs().size();
			for (Integer pos : w) {
				search_res = AlphaBetaSearch.Defend(board, pos, search_moves); // ab.Defend(board,
				for (int i = 0; i < search_res; ++i) {
					if ((libn == 1 || eva.easyEvaluate(search_moves[i], color))
							&& board.isLegal(color, search_moves[i])) {
						defend[search_moves[i]] = true;
						defendWorm[search_moves[i]] = pos;
						++count;
					}
				}
				break;
			}
		}
		if (count > 0) {
			Vertex vex = selectDefend(color);
			int pos = board.makePos(vex.x, vex.y);
			state = DEFEND;
			lastWorm = defendWorm[pos];
			return vex;
		}

		state = UNKNOWN;
		MCManager mc = new MCManager(color, board);
		return mc.MCGen();

	}

	private Vertex selectCapture(Color color) {

		Vector<Integer> vec = new Vector<Integer>();
		int beg = 0;
		for (int i = 0; i < capture.length; ++i) {
			if (capture[i]) {
				vec.add(i);
			}
		}
		MCManager mc = new MCManager(color, board, vec);
		return mc.MCGen();
	}

	private Vertex selectDefend(Color color) {
		Vector<Integer> vec = new Vector<Integer>();
		for (int i = 0; i < defend.length; ++i) {
			if (defend[i]) {
				vec.add(i);
			}
		}
		MCManager mc = new MCManager(color, board, vec);
		return mc.MCGen();
	}

	private Vertex openning(Color color) {
		int star = checkStars();
		if (star != -1) {
			return new Vertex(board.posX(star), board.posY(star));
		}
		List<VertexValue> list = ptnMatcher.getMatch(board, color);
		if (list.size() > 0) {
			for (VertexValue vv : list)
				if (board.isLegal(color, board
						.makePos(vv.vertex.x, vv.vertex.y)))
					return vv.vertex;
		}
		return null;
	}

	private int checkStars() {
		for (int pos : board.getStars())
			if (board.territoryAt(pos) == null)
				return pos;
		return -1;
	}

}
